home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Peter Lewis / Finger 1.3.5 / source / TCP Units / TCPConnections.unit next >
Encoding:
Text File  |  1992-02-24  |  15.7 KB  |  574 lines  |  [TEXT/PJMM]

  1. unit TCPConnections;
  2.  
  3. { This code is part of the Finger/Fingerd source code, written in THINK Pascal 4 }
  4. { Copyright 1991-1992 Peter N Lewis }
  5. { If you use this code, you must give me credit in your about box and documentation }
  6. { This is part of my TCP library of routines }
  7.  
  8. interface
  9.  
  10.     uses
  11.         TCPStuff;
  12.  
  13.     const  { Tuning parameters }
  14.         max_connections = 20;
  15.         tooManyConnections = -23099;
  16.         TO_FindAddress = 40 * 60;
  17.         TO_FindName = 40 * 60;
  18.         TO_ActiveOpen = 20 * 60;
  19.         TO_Closing = 20 * 60;
  20.         TO_PassiveOpen = longInt(10) * 365 * 24 * 3600 * 60;  { Ten years should be safe enough right? :-) }
  21.  
  22.     const
  23.         any_connection = 0;    { Pass to GetConnectionEvent }
  24.         no_connection = -1;    { Guaranteed invalid connection }
  25.  
  26.     type
  27.         connectionIndex = longInt;
  28.         connectionEvent = (C_NoEvent, C_Found, C_SearchFailed, C_NameFound, C_NameSearchFailed,{}
  29.             C_Established, C_FailedToOpen, C_Closing, C_Closed, C_CharsAvailable);
  30.         connectionEventRecord = record
  31.                 event: connectionEvent;
  32.                 connection: connectionIndex;
  33.                 tcpc: TCPConnectionPtr;
  34.                 dataptr: ptr;
  35.                 value: longInt;
  36.                 timedout: boolean;
  37.             end;
  38.  
  39.     function InitConnections (hostFile: str255): OSErr;
  40.     procedure TerminateConnections;
  41.     function CanQuit: boolean;
  42. { After Terminate, keep calling GetConnectionEvent(any_connection,cer) until CanQuit is true, then Finish }
  43.     procedure FinishConnections;
  44.     procedure FinishEverything;  { Or just call FinishEverything }
  45.     function FindAddress (var cp: connectionIndex; hostName: str255; dataptr: univ ptr): OSErr;
  46.     function FindName (var cp: connectionIndex; hostIP: longInt; dataptr: univ ptr): OSErr;
  47.     procedure FindString (hostIP: longInt; var s: str255);
  48.     function NewPassiveConnection (var cp: connectionIndex; localport: integer; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  49.     function NewActiveConnection (var cp: connectionIndex; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  50.     procedure CloseConnection (cp: connectionIndex);
  51.     procedure AbortConnection (cp: connectionIndex); { Violently close connection }
  52.     function GetConnectionEvent (cp: connectionIndex; var cer: connectionEventRecord): boolean;
  53. { Pass any_connection for any event, otherwise cp specifies the event }
  54.     procedure SetDataPtr (cp: connectionIndex; dataptr: univ ptr);
  55.     procedure GetDataPtr (cp: connectionIndex; var dataptr: univ ptr);
  56.     procedure SetConnectionTimeout (cp: connectionIndex; timeout: longInt);
  57.     procedure GetConnectionTimeout (cp: connectionIndex; var timeout: longInt);
  58.     procedure GetConnectionTCPC (cp: connectionIndex; var tcpc: TCPConnectionPtr);
  59.  
  60. implementation
  61.  
  62.     const
  63.         TCPCMagic = 'TCPC';
  64.         TCPCBadMagic = 'badc';
  65.  
  66.     type
  67.         myHostInfo = record
  68.                 hi: hostInfo;
  69.                 done: signedByte;
  70.             end;
  71.         myHostInfoPtr = ^myHostInfo;
  72.         statusType = (CS_None, CS_Searching, CS_NameSearching, CS_Opening, CS_Established, CS_Closing);
  73.         connectionRecord = record
  74.                 magic: OSType;
  75.                 conmagic: longInt;
  76.                 tcpc: TCPConnectionPtr;
  77.                 status: statusType;
  78.                 cacheFaultReturnP: myHostInfoPtr;
  79.                 closedone: boolean;
  80.                 timeout: longInt;
  81.                 dataptr: ptr;
  82.             end;
  83.  
  84.     var
  85.         connections: array[1..max_connections] of connectionRecord;
  86.         connectionItem: connectionIndex;
  87.         dnrptr: ptr;
  88.         connectionmagic: longInt;
  89.  
  90.     function ValidConnection (var cp: connectionIndex): boolean;
  91.         var
  92.             ocp: longInt;
  93.             vc: boolean;
  94.     begin
  95.         vc := false;
  96.         ocp := cp;
  97.         cp := cp mod (max_connections + 1);
  98.         if cp > 0 then
  99.             if connections[cp].magic = TCPCMagic then
  100.                 if connections[cp].conmagic = ocp then
  101.                     vc := true;
  102.         if not vc then
  103.             DebugStr('Invalid Connection');
  104.         ValidConnection := vc;
  105.     end;
  106.  
  107.     procedure SetDataPtr (cp: connectionIndex; dataptr: univ ptr);
  108.     begin
  109.         if ValidConnection(cp) then
  110.             connections[cp].dataptr := dataptr;
  111.     end;
  112.  
  113.     procedure GetDataPtr (cp: connectionIndex; var dataptr: univ ptr);
  114.     begin
  115.         if ValidConnection(cp) then
  116.             dataptr := connections[cp].dataptr
  117.         else
  118.             dataptr := nil;
  119.     end;
  120.  
  121.     procedure SetConnectionTimeout (cp: connectionIndex; timeout: longInt);
  122.     begin
  123.         if ValidConnection(cp) then
  124.             connections[cp].timeout := timeout;
  125.     end;
  126.  
  127.     procedure GetConnectionTimeout (cp: connectionIndex; var timeout: longInt);
  128.     begin
  129.         if ValidConnection(cp) then
  130.             timeout := connections[cp].timeout
  131.         else
  132.             timeout := -1;
  133.     end;
  134.  
  135.     procedure GetConnectionTCPC (cp: connectionIndex; var tcpc: TCPConnectionPtr);
  136.     begin
  137.         if ValidConnection(cp) then
  138.             tcpc := connections[cp].tcpc
  139.         else
  140.             tcpc := nil;
  141.     end;
  142.  
  143.     function MyTCPState (con: TCPConnectionPtr): TCPStateType;
  144.     begin
  145.         if con = nil then
  146.             MyTCPState := T_Closed
  147.         else
  148.             MyTCPState := TCPState(con);
  149.     end;
  150.  
  151. {$S Init}
  152.     function InitConnections (hostFile: str255): OSErr;
  153.         var
  154.             oe, ooe: OSErr;
  155.             i: connectionIndex;
  156.     begin
  157.         for i := 1 to max_connections do
  158.             connections[i].magic := TCPCBadMagic;
  159.         connectionmagic := 0;
  160.         connectionItem := 1;
  161.         oe := TCPInit;
  162.         if oe = noErr then begin
  163.             oe := TCPOpenResolver(hostFile, dnrptr);
  164.             if oe <> noErr then
  165.                 TCPFinish;
  166.         end;
  167.         InitConnections := oe;
  168.     end;
  169.  
  170. {$S Term}
  171.     procedure TerminateConnections;
  172.         var
  173.             i: connectionIndex;
  174.             oe: OSErr;
  175.     begin
  176.         for i := 1 to max_connections do
  177.             with connections[i] do
  178.                 if magic = TCPCMagic then
  179.                     if (status = CS_Established) or (status = CS_Opening) or (status = CS_Closing) then
  180.                         if TCPState(tcpc) <> T_Closed then
  181.                             oe := TCPAbort(tcpc);
  182.     end;
  183.  
  184. {$S Term}
  185.     function CanQuit: boolean;
  186.         var
  187.             i: connectionIndex;
  188.     begin
  189.         CanQuit := true;
  190.         for i := 1 to max_connections do
  191.             if connections[i].magic = TCPCMagic then
  192.                 CanQuit := false;
  193.     end;
  194.  
  195. {$S Term}
  196.     procedure FinishConnections;
  197.     begin
  198.         TCPCloseResolver(dnrptr);
  199.         TCPFinish;
  200.     end;
  201.  
  202. {$S Term}
  203.     procedure FinishEverything;
  204.         var
  205.             cer: connectionEventRecord;
  206.             dummy: boolean;
  207.             er: eventrecord;
  208.             oe: OSErr;
  209.     begin
  210.         TerminateConnections;
  211.         while not CanQuit do begin
  212.             if GetConnectionEvent(any_connection, cer) then begin
  213.                 dummy := WaitNextEvent(everyEvent, er, 0, nil);
  214.             end
  215.             else
  216.                 dummy := WaitNextEvent(everyEvent, er, 5, nil);
  217.         end;
  218.         FinishConnections;
  219.     end;
  220.  
  221. {$S}
  222.     function CreateConnection (var cp: connectionIndex; dp: ptr): OSErr;
  223.     begin
  224.         connectionmagic := connectionmagic + max_connections + 1;
  225.         cp := 1;
  226.         while (connections[cp].magic = TCPCMagic) and (cp < max_connections) do
  227.             cp := cp + 1;
  228.         with connections[cp] do begin
  229.             if magic = TCPCMagic then
  230.                 CreateConnection := tooManyConnections
  231.             else begin
  232.                 magic := TCPCMagic;
  233.                 conmagic := cp + connectionmagic;
  234.                 closedone := false;
  235.                 tcpc := nil;
  236.                 status := CS_None;
  237.                 cacheFaultReturnP := nil;
  238.                 timeout := maxlongInt;
  239.                 dataptr := dp;
  240.                 CreateConnection := noErr;
  241.                 cp := cp + connectionmagic;
  242.             end;
  243.         end;
  244.     end;
  245.  
  246.     procedure DestroyConnection (var cp: connectionIndex);
  247.     begin
  248.         if not ValidConnection(cp) then
  249.             DebugStr('Destroy Connection failed')
  250.         else
  251.             connections[cp].magic := TCPCBadMagic;
  252.         cp := -1;
  253.     end;
  254.  
  255.     function FindAddress (var cp: connectionIndex; hostName: str255; dataptr: univ ptr): OSErr;
  256.         var
  257.             oe: OSErr;
  258.             cpi: connectionIndex;
  259.     begin
  260.         oe := CreateConnection(cp, dataptr);
  261.         if oe = noErr then begin
  262.             cpi := cp;
  263.             if ValidConnection(cpi) then begin
  264.                 with connections[cpi] do begin
  265.                     cacheFaultReturnP := myHostInfoPtr(NewPtr(SizeOf(myHostInfo)));
  266.                     if cacheFaultReturnP = nil then
  267.                         oe := memFullErr
  268.                     else begin
  269.                         cacheFaultReturnP^.done := 0;
  270.                         oe := TCPStrToAddr(dnrptr, hostName, cacheFaultReturnP^.hi, cacheFaultReturnP^.done);
  271.                         if oe = cacheFault then begin
  272.                             timeout := TickCount + TO_FindAddress;
  273.                             oe := noErr;
  274.                         end
  275.                         else begin
  276.                             cacheFaultReturnP^.done := -1;
  277.                             cacheFaultReturnP^.hi.rtnCode := oe;
  278.                         end;
  279.                         status := CS_Searching;
  280.                     end;
  281.                     if oe <> noErr then begin
  282.                         if cacheFaultReturnP <> nil then
  283.                             DisposPtr(ptr(cacheFaultReturnP));
  284.                         DestroyConnection(cp);
  285.                     end;
  286.                 end;
  287.             end;
  288.         end;
  289.         FindAddress := oe;
  290.     end;
  291.  
  292.     procedure FindString (hostIP: longInt; var s: str255);
  293.     begin
  294.         TCPAddrToStr(dnrptr, hostIP, s);
  295.     end;
  296.  
  297.     function FindName (var cp: connectionIndex; hostIP: longInt; dataptr: univ ptr): OSErr;
  298.         var
  299.             oe: OSErr;
  300.             cpi: connectionIndex;
  301.     begin
  302.         oe := CreateConnection(cp, dataptr);
  303.         if oe = noErr then begin
  304.             cpi := cp;
  305.             if ValidConnection(cpi) then begin
  306.                 with connections[cpi] do begin
  307.                     cacheFaultReturnP := myHostInfoPtr(NewPtr(SizeOf(myHostInfo)));
  308.                     if cacheFaultReturnP = nil then
  309.                         oe := memFullErr
  310.                     else begin
  311.                         cacheFaultReturnP^.done := 0;
  312.                         oe := TCPAddrToName(dnrptr, hostIP, cacheFaultReturnP^.hi, cacheFaultReturnP^.done);
  313.                         if oe = cacheFault then begin
  314.                             timeout := TickCount + TO_FindName;
  315.                             oe := noErr;
  316.                         end
  317.                         else begin
  318.                             cacheFaultReturnP^.done := -1;
  319.                             cacheFaultReturnP^.hi.rtnCode := oe;
  320.                         end;
  321.                         status := CS_NameSearching;
  322.                     end;
  323.                     if oe <> noErr then begin
  324.                         if cacheFaultReturnP <> nil then
  325.                             DisposPtr(ptr(cacheFaultReturnP));
  326.                         DestroyConnection(cp);
  327.                     end;
  328.                 end;
  329.             end;
  330.         end;
  331.         FindName := oe;
  332.     end;
  333.  
  334.     function NewPassiveConnection (var cp: connectionIndex; localport: integer; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  335.         var
  336.             oe: OSErr;
  337.             cpi: connectionIndex;
  338.     begin
  339.         oe := CreateConnection(cp, dataptr);
  340.         cpi := cp;
  341.         if ValidConnection(cpi) then
  342.             with connections[cpi] do begin
  343.                 oe := TCPPassiveOpen(tcpc, localPort, remotehost, remoteport, nil);
  344.                 timeout := TickCount + TO_PassiveOpen;
  345.                 status := CS_Opening;
  346.                 if oe <> noErr then
  347.                     DestroyConnection(cp);
  348.             end;
  349.         NewPassiveConnection := oe;
  350.     end;
  351.  
  352.     function NewActiveConnection (var cp: connectionIndex; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  353.         var
  354.             oe: OSErr;
  355.             cpi: connectionIndex;
  356.     begin
  357.         oe := CreateConnection(cp, dataptr);
  358.         cpi := cp;
  359.         if ValidConnection(cpi) then
  360.             with connections[cpi] do begin
  361.                 oe := TCPActiveOpen(tcpc, 0, remotehost, remoteport, nil);
  362.                 timeout := TickCount + TO_ActiveOpen;
  363.                 status := CS_Opening;
  364.                 if oe <> noErr then
  365.                     DestroyConnection(cp);
  366.             end;
  367.         NewActiveConnection := oe;
  368.     end;
  369.  
  370.     procedure CloseConnection (cp: connectionIndex);
  371.         var
  372.             oe: OSErr;
  373.     begin
  374.         if ValidConnection(cp) then
  375.             with connections[cp] do begin
  376.                 if not closedone then begin
  377.                     if MyTCPState(tcpc) <> T_Closed then
  378.                         oe := TCPClose(tcpc, nil);
  379.                     closedone := true;
  380.                 end;
  381.                 status := CS_Closing;
  382.             end;
  383.     end;
  384.  
  385.     procedure AbortConnection (cp: connectionIndex);
  386.         var
  387.             oe: OSErr;
  388.     begin
  389.         if ValidConnection(cp) then
  390.             with connections[cp] do begin
  391.                 if MyTCPState(tcpc) <> T_Closed then
  392.                     oe := TCPAbort(tcpc);
  393.                 status := CS_Closing;
  394.             end;
  395.     end;
  396.  
  397.     function GetConnectionEvent (cp: connectionIndex; var cer: connectionEventRecord): boolean;
  398.         procedure HandleConnection (cp: connectionIndex);
  399.             var
  400.                 oe: OSErr;
  401.                 dummysp: stringPtr;
  402.                 l: integer;
  403.                 rcp: connectionIndex;
  404.         begin
  405.             if (cp < 1) or (cp > max_connections) then
  406.                 DebugStr('GetConnectionEvent:Invalid Connection Index');
  407.             if connections[cp].magic <> TCPCMagic then
  408.                 DebugStr('GetConnectionEvent:Bad TCPCMagic number');
  409.             with connections[cp] do begin
  410.                 rcp := conmagic;
  411.                 cer.connection := rcp;
  412.                 cer.tcpc := tcpc;
  413.                 cer.dataptr := dataptr;
  414.                 cer.timedout := false;
  415.                 case status of
  416.                     CS_NameSearching: 
  417.                         with cacheFaultReturnP^, hi do begin
  418.                             if done <> 0 then begin
  419.                                 if rtnCode = noErr then begin
  420.                                     cer.event := C_NameFound;
  421.                                     SanitizeHostName(rtnHostName);
  422.                                     stringHandle(cer.value) := NewString(rtnHostName);
  423.                                 end
  424.                                 else begin
  425.                                     cer.event := C_NameSearchFailed;
  426.                                     cer.value := rtnCode;
  427.                                 end
  428.                             end
  429.                             else if TickCount > timeout then begin
  430.                                 cer.event := C_NameSearchFailed;
  431.                                 cer.value := 1;
  432.                                 cer.timedout := true;
  433.                             end;
  434.                             if cer.event <> C_NoEvent then begin  { Destroy the connection now }
  435.                                 if done <> 0 then  { If we timed out, then we'll just have to abandon this block.  Oh well }
  436.                                     DisposPtr(ptr(cacheFaultReturnP));
  437.                                 cacheFaultReturnP := nil;
  438.                                 DestroyConnection(rcp);
  439.                             end; {if}
  440.                         end; {with}
  441.                     CS_Searching: 
  442.                         with cacheFaultReturnP^, hi do begin
  443.                             if rtnCode = noErr then begin
  444.                                 cer.event := C_Found;
  445.                                 cer.value := addrs[1];
  446.                             end
  447.                             else if done <> 0 then begin
  448.                                 cer.event := C_SearchFailed;
  449.                                 cer.value := rtnCode;
  450.                             end
  451.                             else if TickCount > timeout then begin
  452.                                 cer.event := C_SearchFailed;
  453.                                 cer.value := 1;
  454.                                 cer.timedout := true;
  455.                             end;
  456.                             if cer.event <> C_NoEvent then begin  { Destroy the connection now }
  457.                                 if done <> 0 then  { If we timed out, then we'll just have to abandon this block.  Oh well }
  458.                                     DisposPtr(ptr(cacheFaultReturnP));
  459.                                 cacheFaultReturnP := nil;
  460.                                 DestroyConnection(rcp);
  461.                             end; {if}
  462.                         end; {with}
  463.                     CS_Opening: 
  464.                         case MyTCPState(tcpc) of
  465.                             T_WaitingForOpen, T_Opening, T_Listening: 
  466.                                 if TickCount > timeout then begin
  467.                                     CloseConnection(rcp);
  468.                                     cer.event := C_FailedToOpen;
  469.                                     cer.timedout := true;
  470.                                 end;
  471.                             T_Established:  begin
  472.                                 cer.event := C_Established;
  473.                                 status := CS_Established;
  474.                                 timeout := maxLongInt;
  475.                             end;
  476.                             T_PleaseClose, T_Closing:  begin
  477.                                 CloseConnection(rcp);
  478.                                 cer.value := 1;
  479.                                 cer.event := C_FailedToOpen;
  480.                                 timeout := TickCount + TO_Closing;
  481.                             end;
  482.                             T_Closed:  begin
  483.                                 status := CS_Closing;
  484.                                 cer.value := 2;
  485.                                 cer.event := C_FailedToOpen;
  486.                                 timeout := TickCount + TO_Closing;
  487.                             end;
  488.                             otherwise
  489.                                 ;
  490.                         end; {case }
  491.                     CS_Established: 
  492.                         case MyTCPState(tcpc) of
  493.                             T_WaitingForOpen, T_Opening, T_Listening: 
  494.                                 DebugStr('Strange State 1');
  495.                             T_Established:  begin
  496.                                 cer.value := TCPCharsAvailable(tcpc);
  497.                                 if cer.value > 0 then
  498.                                     cer.event := C_CharsAvailable;
  499.                             end;
  500.                             T_PleaseClose, T_Closing:  begin
  501.                                 cer.value := TCPCharsAvailable(tcpc);
  502.                                 if cer.value > 0 then
  503.                                     cer.event := C_CharsAvailable
  504.                                 else begin
  505. {    CloseConnection(rcp);}
  506.                                     status := CS_Closing;
  507.                                     cer.event := C_Closing;
  508.                                     timeout := TickCount + TO_Closing;
  509.                                 end;
  510.                             end;
  511.                             T_Closed:  begin
  512.                                 status := CS_Closing;
  513.                                 cer.event := C_Closing;
  514.                                 timeout := TickCount + TO_Closing;
  515.                             end;
  516.                             otherwise
  517.                                 ;
  518.                         end;
  519.                     CS_Closing: 
  520.                         case MyTCPState(tcpc) of
  521.                             T_WaitingForOpen, T_Opening, T_Listening: 
  522.                                 DebugStr('Strange State 2');
  523.                             T_PleaseClose, T_Closing, T_Established:  begin
  524.                                 cer.value := TCPCharsAvailable(tcpc);
  525.                                 if cer.value > 0 then
  526.                                     cer.event := C_CharsAvailable
  527.                                 else if TickCount > timeout then begin
  528.                                     cer.event := C_Closed;
  529.                                     if tcpc <> nil then
  530.                                         oe := TCPRelease(tcpc);
  531.                                     cer.timedout := true;
  532.                                     DestroyConnection(rcp);
  533.                                 end;
  534.                             end;
  535.                             T_Closed:  begin
  536.                                 cer.event := C_Closed;
  537.                                 if tcpc <> nil then
  538.                                     oe := TCPRelease(tcpc);
  539.                                 DestroyConnection(rcp);
  540.                             end;
  541.                             otherwise
  542.                                 ;
  543.                         end;
  544.                     otherwise
  545.                         ;
  546.                 end;
  547.             end;{with}
  548.         end;{HandleConnection}
  549.         var
  550.             oci: connectionIndex;
  551.     begin
  552.         cer.event := C_NoEvent;
  553.         if cp <> any_connection then begin
  554.             if ValidConnection(cp) then
  555.                 HandleConnection(cp);
  556.         end
  557.         else begin
  558.             oci := connectionItem;
  559.             repeat
  560.                 if connections[connectionItem].magic = TCPCMagic then begin
  561.                     HandleConnection(connectionItem);
  562.                     if cer.event <> C_NoEvent then
  563.                         leave;
  564.                 end;{if}
  565.                 if connectionItem = max_connections then
  566.                     connectionItem := 1
  567.                 else
  568.                     connectionItem := connectionItem + 1;
  569.             until oci = connectionItem;
  570.         end;{if}
  571.         GetConnectionEvent := cer.event <> C_NoEvent;
  572.     end;{GetConnectionEvent}
  573.  
  574. end.